package cn.iocoder.yudao.module.engine.service.core.pipeline;

import cn.iocoder.yudao.module.engine.model.context.ControlEngineContext;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FilterContext {
    volatile FilterContext next;
    volatile FilterContext prev;
    private static final int ADDED = 1;
    private static final int REMOVED = 2;
    private static final int INIT = 0;
    private int state;
    private final IFilter filter;
    private final FilterPipeline pipeline;
    private final String name;

    public FilterContext(FilterPipeline pipeline, IFilter filter, String name) {
        this.pipeline = pipeline;
        this.filter = filter;
        this.name = name;
        state = INIT;
    }

    public FilterPipeline getPipeline() {
        return pipeline;
    }

    public void setAdded() {
        state = ADDED;
    }

    public void setRemoved() {
        state = REMOVED;
    }

    public String getName() {
        return name;
    }

    public IFilter getFilter() {
        return filter;
    }

    public void write(ControlEngineContext obj) {
        if (obj == null) {
            throw new NullPointerException("writeCommand event is null");
        }
        FilterContext next = findOutboundNext();
        invokeWrite(next, obj);
    }

    public void fireRead(ControlEngineContext obj) {
        FilterContext next = findInboundNext();
        invokeRead(next, obj);
    }

    private FilterContext findInboundNext() {
        return next;
    }

    private FilterContext findOutboundNext() {
        return prev;
    }

    private boolean isAdded() {
        return state == ADDED;
    }

    static void invokeRead(final FilterContext next, ControlEngineContext obj) {
        log.info("执行read, filter = {}", next.getFilter().getClass());
        next.invokeRead(obj);
    }

    private void invokeRead(ControlEngineContext obj) {
        if (isAdded()) {
            try {
                getFilter().read(this, obj);
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    throw new RuntimeException(e);
                }
            }
        } else {
            fireRead(obj);
        }
    }

    static void invokeWrite(final FilterContext next, ControlEngineContext obj) {
        log.info("执行write, filter = {}", next.getFilter().getClass());
        try {
            next.invokeWrite(obj);
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            } else {
                throw new RuntimeException(e);
            }
        }
    }

    private void invokeWrite(ControlEngineContext obj) throws Exception {
        if (isAdded()) {
            getFilter().write(this, obj);
        } else {
            write(obj);
        }
    }

}
